set auto_path [concat [pwd]/../../pkg/tkMD $auto_path ]
## start script
if {[lsearch $argv --DEBUG] >= 0 } {
set DEBUG true
} else {
set DEBUG false
}

## main
if [ catch {package require tkMD 1.1}] { puts "$argv0 needs tkMD 1.1, please install it first!";exit}
namespace import SimTask::*
namespace import Path::*

proc main {argc argv} {
global argv0 tcl_version
if { $tcl_version < 8.5 } {
    puts "Cannot run, tkMD requires Tcl version higher than 8.5."
    exit
}

#args help 
proc print_help {} {
    global argv0
 puts "Usage:\n $argv0 paramterfile \[--peptide peptide1 peptide2\] \[ --petidelist peptidefile1 peptidefile2 ...\] \[--set-varname value1 \[value2\]...\] " 
 puts "Input:\n"
 puts "    paramterfile : a file to setup all the parameters needed for simulations (find example files in the current folder)."
  puts "Options:\n"
 puts "    \[--peptide peptide1 peptide2 ...\] : list the peptides that are going to be simulated. "
 puts "    \[--peptidelist peptidefile1 peptidefile2 ...\] : files that list the peptides going to be simulated."
 puts "    \[--runpath \] : directory to save simulation files. Default is a subfolder of the current directory named by the parameterfile. If there already are simulation files existed in the directory, only unfinished simulations(without eql_min.crd) will be redo."
 puts "    \[--pdbpath \] : place to look for pdb files. Default is subfolder named pdb under current directory." 
 puts "    \[--templatepath \] : place to look for template files. Default is a subfolder named template under current directory." 
 puts "    \[--num-peptide \] : numbers of peptides in pores."
 puts "    \[--pot-file \] : path pattern for potential files. Use @replacable for unknown parameters."
 puts "    \[--use-charmm \] : which charmm binary file is going to be used."
 puts "    \[--X \] : run each simulation n times."
 puts "    \[ --norun \] : just prepares the files but does not do calculations."
 puts "    \[--clean \] : remove all the CHARMM output files after the simulation to save disk space. Otherwise those files will be compressed into tar files."
 puts "Example:\n"
 puts "$argv0 flat.para --peptide 2mag --set-membrane dmpc dopc --set-potfile ../pot/@membrane/pot.dx "

}
proc parse_cmd {} {
    global argc argv 
    #get options 
    set options [lsearch -all -glob $argv "--*" ]
    set i 0
    foreach idx  $options {
    set end [expr [lindex $options [expr $i+1]]-1]
    if {$end <0} {set end end}
    set name [lindex $argv $idx]
    set value [lrange $argv [expr $idx +1] $end]
    set Option($name) $value
    incr i
    }
    if {[llength $options]>0} {set argv [lrange $argv 0 [expr [lindex $options 0]-1] ]}
    if {[llength $argv]< 1} {
        puts "Paramter File is required!"
        print_help
        exit
    }
        # do the parsing for required arguments
    global parameterfile basepath SimTask::RunPath SimTask::Pdbpath
    set parameterfile [lindex $argv 0]
    if ![file exists $parameterfile] {puts "Parameter File $parameterfile Do not exists!";print_help;exit}
    set basename [lindex [split [file rootname $parameterfile] /] end]
    set SimTask::RunPath [pwd]/$basename 
    uplevel 1 "source $parameterfile"
    if { [llength [array names Option --set-*]] > 0 } {
        set ofid [open $parameterfile a]
        set timestamp [clock format [clock click] -format "%b %d %y - %T"]
        puts $ofid "# Added parameter @ $timestamp"
    }
    # do the parsing for options 
    global peptides
    foreach name [lsort [array names Option]] {
        switch -nocase -glob $name {
        --peptide { 
                Data::ladd peptides $Option(--peptide) 
            }
        --peptidelist {
                foreach pdblistfile $Option(--peptidelist) {
                 Data::ladd peptides [regexp -all -inline -- {\S+} [read [open $pdblistfile r] ]]
                }
            }
        --output-pattern {
            global outputpattern
            set outputpattern [lindex $Option(--output-pattern) 0]
        }
        --pdbpath {
                set SimTask::Pdbpath [lindex $Option(--pdbpath) 0]
                if ![file isdirectory ${SimTask::Pdbpath}] { 
                    puts "PDB path ${SimTask::Pdbpath} is not correct!"
                    print_help
                    exit
                }
                if ![file exists ${SimTask::Pdbpath}] {
                    puts "PDB path ${SimTask::Pdbpath} do not exist!"
                    print_help
                    exit
                }
            }
         --runpath {
                set SimTask::RunPath [lindex $Option(--runpath) 0]
                if {[string match [file pathtype $SimTask::RunPath] relative ] } { set SimTask::RunPath [pwd]/$SimTask::RunPath}
                if ![file exists ${SimTask::RunPath}] {
                    Path::mk_path $SimTask::RunPath
                }
                if ![file isdirectory ${SimTask::RunPath}] { 
                    puts "Output path ${SimTask::RunPath} is not correct!"
                    print_help
                    exit
                }
         }
         --templatepath {
                set SimTask::TemplatePath [lindex $Option(--templatepath) 0]
                if ![file isdirectory ${SimTask::TemplatePath}] { 
                    puts "Template path ${SimTask::TemplatePath} is not correct!"
                    print_help
                    exit
                }
                if ![file exists ${SimTask::TemplatePath}] {
                    puts "Template path ${SimTask::TemplatePath} do not exist!"
                    print_help
                    exit
                }
         }
         --pot-path {
                global potfile 
                set potfile [lindex $Option(--pot-path) 0]
         }
         --num-peptide {
                global npeptide
                set npeptide [lindex $Option(--num-peptide) 0]
         }
         --jobpath {
                set SimTask::JobPath [lindex $Option(--jobpath) 0]
                if ![file isdirectory ${SimTask::JobPath}] { 
                    puts "Job path ${SimTask::JobPath} is not correct!"
                    print_help
                    exit
                }
                if ![file exists ${SimTask::JobPath}] {
                    puts "Job path ${SimTask::JobPath} do not exist!"
                    print_help
                    exit
                }
         }
         --use-charmm {
               set SimTask::Charmmbin [lindex $Option(--use-charmm) 0]
         }
         --X {
               global nreplica
               set nreplica [lindex $Option(--X) 0]
         }
         --clean {
               global docleanning
                set docleanning true
         }
        --set-* {
                global CmdValues
                if {[llength $Option($name)] < 1} {puts "Use --set-varname value1 \[value2\]...";print_help}
                set varname [string range $name 6 end]
                set value [lrange $Option($name) 0 end]
                if {[llength $value ] < 2 } { set value [lindex $value 0] }
                set CmdValues($varname) $value 
                upvar #1 $varname Var
                set Var $value
                puts $ofid "set $varname $value"
            }
         };#end of switch
    };#end of foreach 
    if { [llength [array names Option --set-*]] > 0 } {
        close $ofid
    }
}


#Default simulation environment
global SimTask::PdbPath SimTask::TemplatePath SimTask::JobPath SimTask::RunPath SimTask::Njobs nreplica docleanning
set SimTask::PdbPath [pwd]/../pdb 
set SimTask::TemplatePath [pwd]/template
set SimTask::JobPath [pwd]/job
set SimTask::RunPath [pwd]/run

set outputpattern array(key)_value/ 
#Default simulation parameters
global type temp thick ionc anfr preptime eqltime peptides orientation
set type flat 
set temp 298
set membrane dmpc
array set ThickDict { dlpc 19.5 dmpc 23.5 dopc 26 popc 27 }
set thick @ThickDict(@membrane)
set r0 { [ getRadius @thick ] }
proc getRadius { thick } {
   return [expr double($thick)/2 ]
}
set k0 0
set ionc 0.1
set anfr 0.3
set preptime 0.001
set eqltime 0.001
set orientation { o0 }
set peptides {}
set npeptide 1
set sep 1.0
set nreplica 4
set docleanning false
set ih_percentage 1.0
parse_cmd
VarSpace options { type membrane temp  thick r0 k0 sep npeptide ThickDict ionc anfr ih_percentage orientation preptime eqltime potfile }
# validate parameters

if {[llength $peptides] <= 0} {
    puts "Please indicate which peptides to be simulated by set variable peptides in your parameter file or by supply --peptide/--petidelist option to command line."
    print_help
    exit
}
if [catch {set binpath [exec which $SimTask::Charmmbin]} ] {
    puts "CHARMM Binary file does not exist or is not set up correctly!"
    print_help
    exit
}

#start
set timestamp [clock format [clock click] -format "%b %d %y - %T"]
puts "Start Simulation with { $argv0 $argv } @ $timestamp "
puts "==============================================================="
printEnv
puts "==============================================================="
puts "Peptides to be simulated:"
puts "==============================================================="
puts "$peptides"
puts "==============================================================="
puts "Parameters will be using for simulations: "
puts "==============================================================="
foreach var $options(*vars) {
   puts "$var = $options(def,$var)"
}
puts "==============================================================="

foreach peptide $peptides {
set timestamp [clock format [clock seconds] -format "%b %d %y - %T"]
puts "Prepare: $peptide , Current Time: $timestamp "
puts "==============================================================="

if [catch {
        prepfiles $peptide {o0.crd o1.crd o2.crd o3.crd o4.crd pept.psf}
    switch $type {
       flat {
       }
       cylindrical {
        run $nreplica $peptide gen_oligomer.inp options --combinejob run orientation --skip { file exists pepts.crd} 
       }
       toroidal {
        run $nreplica $peptide gen_oligomer.inp options --combinejob run orientation --skip { file exists pepts.crd} 
       }
    }
	} error] {	puts "ERROR: $error" }

} 
SimTask::waitfor run
foreach peptide $peptides {
set timestamp [clock format [clock seconds] -format "%b %d %y - %T"]
puts "Do: $peptide , Current Time: $timestamp "
puts "==============================================================="

if [catch {
    switch $type {
       flat {
    	run $nreplica $peptide run.inp options --combinejob run orientation --pre { ln -s $potfile pot.dx } --skip { file exists eql_min.crd } --post { tar -czf run.out.tar.gz run.out; rm run.out}
       }
       cylindrical {
    	run $nreplica $peptide run.inp options --combinejob run orientation --pre { ln -s $potfile pot.dx } --skip { file exists eql_min.crd } --post { tar -czf run.out.tar.gz run.out; rm run.out}
       }
       toroidal {
    	run $nreplica $peptide run.inp options --combinejob run orientation --pre { ln -s $potfile pot.dx } --skip { file exists eql_min.crd } --post { tar -czf run.out.tar.gz run.out; rm run.out}
       }
    }
	} error] {	puts "ERROR: $error" }

} 
SimTask::waitfor run
if $docleanning { rmfiles $SimTask::RunPath  *.out.tar.gz }
puts "Simulations are all finished. But check the error log(under the job path) to see if all simulations are carried out correctly. Errors are suppressed during the simulation to prevent the program exits accidentally."
};#end of main

# execuate 
if [catch {main $argc $argv } error ] {
   puts "Internal Error occured in program $argv0!"
   if [info exists DEBUG] { puts $::errorInfo} else { puts $error }
   # send error message to developer?
   set core [open core.dump w]
   puts $core "Error when execuate $argv0 $argv\n $::errorInfo"
   close $core 
   if [info exists SENDDEBUG] {
    if ![catch { exec mail -s "BUG report for $argv0" he.yi.ustcer@gmail.com < core.dump}] {
     #try mail 
    } elseif ![ catch { exec sendmail2 0 }] {
     #try sendmail 
    } elseif ![catch { package require smtp}] {
     #try smtp 
     smtp::sendmessage "Error when execuate $argv0 $argv\n $::errorInfo" \
        -header[list Subject "BUG report for $argv0"] \
        -header[list From yi.he.ustcer@gmail.com] \
        -header[list To yi.he.ustcer@gmail.com]] \
        -servers smtp.gmail.com
    } else {
      #do nothing
     }
   }
    file delete core.dump
}


exit
